package top.dzygod.modules.mp.rest;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import top.dzygod.annotation.Log;
import top.dzygod.annotation.rest.AnonymousGetMapping;
import top.dzygod.annotation.rest.AnonymousPostMapping;
import top.dzygod.modules.mp.domain.Order;
import top.dzygod.modules.mp.service.OrderService;
import top.dzygod.modules.pay.domain.Record;
import top.dzygod.modules.pay.service.RecordService;
import top.dzygod.modules.system.service.DictService;
import top.dzygod.modules.system.service.dto.DictDetailDto;
import top.dzygod.modules.system.service.dto.DictDto;
import top.dzygod.modules.system.service.dto.DictQueryCriteria;
import top.dzygod.utils.ElAdminConstant;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Author: dingziyuan
 * @Date: 2020/2/17/017 9:24
 * @Description: 会员注册调用的公众号接口
 */
@RestController
@RequestMapping("/api/mp")
@Slf4j
public class MpUserController {

    @Resource
    private WxMpService wxMpService;
    @Resource
    private WxPayService wxService;
    @Resource
    private OrderService orderService;
    @Resource
    private  RecordService recordService;
    @Resource
    private DictService dictService;

    public static String time;

    /**
     * 注册：会员跳转注册页面时调用服务号公众号接口，将地址返回给前端
     *
     * @return
     */
    @AnonymousGetMapping
    @Log("确认用户授权")
    @ApiOperation("获取授权")
    @ResponseBody
    public String oauth2URL() {
        // 服务号openid
        wxMpService.switchover(ElAdminConstant.mpMessage.SERVING_APP_ID.getValue());

        time = DateUtil.timer(Boolean.TRUE).toString();

        return wxMpService.oauth2buildAuthorizationUrl(ElAdminConstant.mpMessage.REDIRECT_URI.getValue(),
                "snsapi_userinfo", time);
    }

    @AnonymousGetMapping(value = "/getConfig")
    @Log("前端注册")
    @ApiOperation("获取config注册")
    public ResponseEntity<Object> sendConfig(@RequestParam  String url) {

        try {
            WxJsapiSignature signature = wxMpService.createJsapiSignature(url);
            return new ResponseEntity<>(signature, HttpStatus.OK);
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return new ResponseEntity<>(HttpStatus.OK);
    }

    @AnonymousGetMapping("/sign")
    @Log("签名")
    @ApiOperation("签名")
    public ResponseEntity<Object> sign(HttpServletRequest httpServletRequest,  @RequestParam String code,@RequestParam String state) {

        if (!time.equals(state)) {
            return new ResponseEntity<>("",HttpStatus.CONTINUE);
        }
        // 微信可能会发两次回调,第一次的时候改一下全局变量,第二次就不会往下走了
        time = DateUtil.timer(Boolean.TRUE).toString();


        // 客户端ip
        String ip = httpServletRequest.getHeader("X-Forwarded-For");
        if (!ObjectUtils.isEmpty(ip)) {
            ip = ip.split(",")[0];
        } else {
            ip = httpServletRequest.getHeader("'X-Real-IP");
        }

        // 字典获取描述与金额
        DictQueryCriteria dictQueryCriteria = new DictQueryCriteria();
        dictQueryCriteria.setBlurry("pay");
        List<DictDetailDto> details = dictService.queryAll(dictQueryCriteria).get(0).getDictDetails();

        try {
            WxMpOAuth2AccessToken  token = wxMpService.oauth2getAccessToken(code);
            WxMpUser user = wxMpService.oauth2getUserInfo(token, "zh_CN");


            // 商品描述
            String body = details.get(0).getValue();
            // 缴费金额
            Integer totalFee = Integer.parseInt(details.get(1).getValue());
            // 订单号
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
            String outTradeNo = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
            String tradeNo = new String(outTradeNo.getBytes(), StandardCharsets.UTF_8);
            // openId
            String openId = new String(user.getOpenId().getBytes(), StandardCharsets.UTF_8);
            // ip
            String cliId = new String(ip.getBytes(), StandardCharsets.UTF_8);
            // 回调地址
            String value = ElAdminConstant.mpMessage.NOTIFY_URI.getValue();
            String notifyUrl = new String(value.getBytes(), StandardCharsets.UTF_8);
            // 支付类型
            String tradeType = new String("JSAPI".getBytes(), StandardCharsets.UTF_8);

            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            request.setBody(body);
            request.setOpenid(openId);
            request.setOutTradeNo(tradeNo);
            request.setTotalFee(totalFee);
            request.setSpbillCreateIp(cliId);
            request.setNotifyUrl(notifyUrl);
            request.setTradeType(tradeType);
            WxPayUnifiedOrderResult result = wxService.unifiedOrder(request);

            if ("SUCCESS".equals(result.getReturnCode()) && "SUCCESS".equals(result.getResultCode())){
                // 二次签名
                final Map<String, String> map = new TreeMap<>();
                map.put("appId", result.getAppid());
                map.put("timeStamp", String.valueOf(Instant.now().toEpochMilli()));
                map.put("nonceStr", String.valueOf(System.currentTimeMillis()));
                map.put("package", "prepay_id=" + result.getPrepayId());
                map.put("signType", "MD5");
                map.put("paySign", SignUtils.createSign(map, map.get("signType")
                        , wxService.getConfig().getMchKey(), null));
                map.put("tradeNo", tradeNo);
                map.put("openId", openId);
                map.put("totalFee", String.valueOf(totalFee));
                return new ResponseEntity<>(map, HttpStatus.OK);
            }

            return new ResponseEntity<>(result.getErrCode(), HttpStatus.OK);

        } catch (WxPayException | WxErrorException e) {
            e.printStackTrace();
        }

        return new ResponseEntity<>(HttpStatus.CONTINUE);

    }

    @AnonymousPostMapping(value = "/notify")
    @Log(value = "支付回调")
    @ApiOperation(value = "支付回调接口")
    public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
        final WxPayOrderNotifyResult result = this.wxService.parseOrderNotifyResult(xmlData);
        // 真实性校验
        result.checkResult( wxService,null,true);
            if ("SUCCESS".equals(result.getResultCode())){
                Order order = orderHandle(result);
                orderService.create(order);
                return WxPayNotifyResponse.success("成功");
            }else{
                return WxPayNotifyResponse.fail("失败");
            }
    }

    @ApiOperation(value = "查询订单")
    @AnonymousGetMapping("/queryOrder")
    public WxPayOrderQueryResult queryOrder(@RequestParam(required = false) String transactionId,
                                            @RequestParam(required = false) String outTradeNo) throws WxPayException {
        return this.wxService.queryOrder(transactionId, outTradeNo);
    }

    @ApiOperation("移动端添加记录")
    @Log("移动端添加记录")
    @AnonymousPostMapping
    public ResponseEntity<Object> create(@RequestBody Record resources){
        return new ResponseEntity<>(recordService.create(resources),HttpStatus.CREATED);
    }


    /**
     * 订单bean处理
     * @param result
     * @return
     */
    private Order orderHandle(WxPayOrderNotifyResult result){
        Order order = new Order();
        order.setAppId(result.getAppid());
        order.setBankType(result.getBankType());
        order.setOpenId(result.getOpenid());
        order.setCashFee(result.getCashFee());
        order.setTotalFee(result.getTotalFee());
        order.setFeeType(result.getFeeType());
        order.setTotalFee(result.getTotalFee());
        order.setIsSubscribe(result.getIsSubscribe());
        order.setMchId(result.getMchId());
        order.setNonceStr(result.getNonceStr());
        order.setOutTradeNo(result.getOutTradeNo());
        order.setTradeType(result.getTradeType());
        order.setTransactionId(result.getTransactionId());
        order.setTimeEnd(result.getTimeEnd());
        order.setSign(result.getSign());

        return order;
    }
}

